枚举

  一个枚举是一个类型,它可以保存一组由用户刻画的值。一旦定义之后,枚举的使用就很像是一个整数类型。

  命名的整数常量可以定义为枚举的成员。例如

enum { ASM, AUTO, BREAK };

这就定义了三个被称为枚举符的整数常量,并给他们赋了值。按默认方式,枚举符所赋的值从0开始递增,所以ASM == 0,AUTO == 1,BREAK == 2。枚举也可以命名,例如,

enum keyword { ASM, AUTO, BREAK };

每个枚举都是一个独立的类型,枚举符的类型就是它所在的那个枚举。例如,AUTO的类型就是keyword。

  将一个变量声明为keyword而不是一个普通的int,能够给用户和编译器一些有关该变量拟议中的用途的提示。例如,

    void f(keyword key)
    {
        switch(key)
        {
        case ASM:
            // 做某些事情
            break;
        case BREAK:
            // 做某些事情
            break;
        }
    }

编译器由可能提出一个警告,因为在三个keyword值中只有两个被处理了。

  枚举符也可以用整型(4.1.1节)的constant-expression(常量表达式)(C.5节)进行初始化。如果某个枚举中所有枚举符的值均非负,该枚举的表示范围就是[0:2的k次方 - 1],其中的2的k次方是能使所有枚举符位于此范围内的最小的2的幂;如果存在负的枚举符值,该枚举的取值范围就是[-2的k次方 : 2的k次方-1]。这样就定义了一个最小的位段,其中能保存所有枚举符值的常规2补码表示,例如,

    enum e1 { dark, light };     // 范围0:1
    enum e2 { a = 3, b = 9 };    // 范围0:15
    enum e3 { min = -10, max = 1000000 };    // 范围 -1048576:1048575

一个整型值可以显式地转换到一个枚举值。除非这种转换的结果位于该枚举的范围之内,否则就是无定义的。例如,

    enum flag { x = 1, y = 2, z = 4, e = 8 };    // 范围0:15

    flag f1 = 5;            // 类型错❌:5不是flag类型
    flag f2 = flag(5);      // 可以:flag(5)是flag类型且在flag的范围之内

    flag f3 = flag(z|e);    // 可以:flag(12)是flag类型且在flag的范围之内
    flag f4 = flag(99);     // 无定义:99不在flag的范围之内

最后一个赋值说明了为什么不允许隐式地从整数转换到枚举:大部分整数值在特定的枚举里都没有对应的表示。

  有关枚举的值范围的概念与Pascal一族语言中的枚举概念不同。无论如何,有关按位操作的各种例子在C和C++里已经有很长的历史了,其中都要求对超出枚举符集合的值有良好的定义。

  一个枚举的sizeof就是某个能够容纳其范围的整型的sizeof,而且不会大于sizeof(int),除非有某个枚举符的值不能用int也不能用unsigned int表示。举例来说,在sizeof(int) == 4的机器上,sizeof(e1)可以是1,也可能是4,但绝对不会是8。

  按照默认方式,枚举可以转换到整数去参加算术运算(6.2节)。一个枚举是一个用户定义类型,所以用户可以为枚举定义它自身的操作,例如定义++或<<(11.2.3节)。

🔚